package com.teamfractal.fracdustry.common.data.recipes;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.teamfractal.fracdustry.common.block.impl.machines.FDOreProcessorBlock;
import com.teamfractal.fracdustry.common.config.FDCommonConfig;
import com.teamfractal.fracdustry.common.data.recipes.init.FDRecipeTypes;
import net.minecraft.core.NonNullList;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.Container;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.item.crafting.ShapedRecipe;
import net.minecraft.world.level.Level;
import net.minecraftforge.registries.ForgeRegistryEntry;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public class OreProcessorRecipe implements IOreProcessorRecipe {

    private final ResourceLocation id;
    private final ItemStack output;
    private final NonNullList<Ingredient> recipeItems;

    public OreProcessorRecipe(ResourceLocation id, ItemStack output, NonNullList<Ingredient> recipeItems) {
        this.id = id;
        this.output = output;
        this.recipeItems = recipeItems;
    }


    @Override
    public boolean matches(Container inv, @Nonnull Level world) {
        return recipeItems.get(0).test(inv.getItem(0));
    }

    @Nonnull
    @Override
    public NonNullList<Ingredient> getIngredients() {
        return recipeItems;
    }

    //Get Crafting Result
    @Nonnull
    @Override
    public ItemStack assemble(@Nonnull Container container) {
        return output.copy();
    }

    @Nonnull
    @Override
    public ItemStack getResultItem() {
        return output.copy();
    }

    public static int getProcess() {
        return Math.max(FDCommonConfig.ORE_PROCESSOR_BASE_PROCESS_TIME.get(),1);
    }

    @Nonnull
    public ItemStack getToastSymbol() {
        return new ItemStack(FDOreProcessorBlock.BLOCK);
    }

    @Nonnull
    @Override
    public ResourceLocation getId() {
        return id;
    }

    @Nonnull
    @Override
    public RecipeSerializer<?> getSerializer() {
        return FDRecipeTypes.recipeSerializerOreProcessor.get();
    }

    public static class OreProcessorRecipeType implements RecipeType<OreProcessorRecipe> {
        @Override
        public String toString() {
            return IOreProcessorRecipe.TYPE_ID.toString();
        }
    }

    public static class Serializer extends ForgeRegistryEntry<RecipeSerializer<?>>
            implements RecipeSerializer<OreProcessorRecipe> {

        @Nonnull
        @Override
        public OreProcessorRecipe fromJson(@Nonnull ResourceLocation recipeId, @Nonnull JsonObject json) {
            ItemStack output = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "output"));

            JsonArray ingredients = GsonHelper.getAsJsonArray(json, "ingredients");
            NonNullList<Ingredient> inputs = NonNullList.withSize(1, Ingredient.EMPTY);

            for (int i = 0; i < inputs.size(); i++) {
                inputs.set(i, Ingredient.fromJson(ingredients.get(i)));
            }

            return new OreProcessorRecipe(recipeId, output,
                    inputs);
        }

        @Nullable
        @Override
        public OreProcessorRecipe fromNetwork(@Nonnull ResourceLocation recipeId, FriendlyByteBuf buffer) {
            int i = buffer.readVarInt();
            NonNullList<Ingredient> inputs = NonNullList.withSize(i, Ingredient.EMPTY);

            for (int j = 0; j < inputs.size(); j++) {
                inputs.set(j, Ingredient.fromNetwork(buffer));
            }

            ItemStack output = buffer.readItem();
            return new OreProcessorRecipe(recipeId, output,
                    inputs);
        }

        @Override
        public void toNetwork(FriendlyByteBuf buffer, OreProcessorRecipe recipe) {
            buffer.writeVarInt(recipe.getIngredients().size());
            for (Ingredient ing : recipe.getIngredients()) {
                ing.toNetwork(buffer);
            }
            buffer.writeItemStack(recipe.getResultItem(), false);
        }
    }
}
